<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Core
 * @package    Core_Auth
 * @subpackage Core_Auth_Adapter
 */

/**
 * @see Zend_Auth_Adapter_Interface
 */
require_once 'Zend/Auth/Adapter/Interface.php';
require_once 'Zend/Auth/Result.php';
require_once 'facebook.php';
require_once 'Core/Resource.php';
require_once 'Core/User/Token.php';
require_once 'Core/User.php';

/**
 * A Zend_Auth Authentication Adapter allowing the use of Facebook as an authentication source.
 * Note that the auth adapter does not perform any redirects.
 *
 * @category   Core
 * @package    Core_Auth
 * @subpackage Core_Auth_Adapter
 */
class Core_Auth_Adapter_Facebook implements Zend_Auth_Adapter_Interface {
	
	/**
	 * Instance of the facebook api.
	 * 
	 * @var Facebook
	 */
	private $_fb;
	
	/**
	 * Post authorization url.
	 * 
	 * @var string
	 */
	private $_nextUrl = '';
	
	/**
	 * Cancel URL.
	 * 
	 * @var string
	 */
	private $_cancelUrl = '';
	
	/**
	 * Requested Permissions
	 * 
	 * @var string
	 */
	private $_perms = '';
	
	/**
	 * Sets the value of the cancellation url.
	 *
	 * @param  string $appId The cancel url
	 * @return Zend_Auth_Adapter_Facebook Provides a fluent interface
	 */
	public function setCancelUrl($cancelUrl) {
		$this->_cancelUrl = $cancelUrl;
		return $this;
	}
	
	/**
	 * Sets the value of the next url.
	 *
	 * @param  string $appId The next url
	 * @return Zend_Auth_Adapter_Facebook Provides a fluent interface
	 */
	public function setNextUrl($nextUrl) {
		$this->_nextUrl = $nextUrl;
		return $this;
	}
	
	
	/**
	 * Sets the requested permissions
	 *
	 * @param  string $appId Comma separated list of permissions.
	 * @return Zend_Auth_Adapter_Facebook Provides a fluent interface
	 */
	public function setPerms($perms) {
		$this->_perms = $perms;
		return $this;
	}
	
	/**
	 * Constructor
	 *
	 * @param string $appId the application ID
	 * @param string $secret the application secret
	 * @param string $scope the application scope
	 * @param string $redirectUri the URI to redirect the user to after successful authentication
	 */
	public function __construct($nextUrl = '', $cancelUrl = '', $perms = '') {
		$this->_fb = Core_Resource::locate ( 'facebook' );
		$this->_cancelUrl = $cancelUrl;
		$this->_nextUrl = $nextUrl;
		$this->_perms = $perms;
	}
	
	/**
	 * Authenticates the user against facebook
	 * Defined by Zend_Auth_Adapter_Interface.
	 *
	 * @throws Zend_Auth_Adapter_Exception If answering the authentication query is impossible
	 * @return Zend_Auth_Result
	 */
	public function authenticate() {
		
		// Can we read the facebook ID?
		try {
			$fb_user = $this->_fb->api ( '/me' );
		} catch ( FacebookApiException $e ) {
			
			// Looks like we can't read the user. Inform the auth adapter and return a redirect url.
			$url = $this->_fb->getLoginUrl ( array ('cancel_url' => $this->_cancelUrl, 'next' => $this->_nextUrl, 'req_perms' => $this->_perms ) );
			
			return new Zend_Auth_Result ( Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID, null, array ('redirect' => $url ) );
		}
		
		// Try to find a token based on the facebook ID.
		$userToken = Core_User_Token::findTokenByRemoteUserId ( $fb_user ['id'], Core_User_Token::TYPE_FACEBOOK );
		
		// Do we have a token?
		if (! empty ( $userToken )) {
			// We have a valid token, let's login.
			
			$user = Core_User::factory ( $userToken->userId );
			return new Zend_Auth_Result ( Zend_Auth_Result::SUCCESS, $user->email );

		} else if (! empty ( $fb_user )) {
			
			// Do we have an email address conflict?
			$user = Core_User::factory ( $fb_user ['email'] );
			
			if (empty ( $user )) {
				// We don't have this person, or their email address, in the database
				return new Zend_Auth_Result ( Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND, null );
			} else {
				// WE've already got an email address, something's weird.
				return new Zend_Auth_Result ( Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS, null );
			}
		}
		
		// WTF?
		return new Zend_Auth_Result ( Zend_Auth_Result::FAILURE_UNCATEGORIZED );

	}
}
